<?php
final class G
{
    public static function p404 ($s='') {
        header("HTTP/1.1 404 Not Found");
        $tpl = G::tpl();
        $tpl->assign('msg',$s);
        $tpl->display(_TPL._DS.'404.html');
        die();
    }
    public static function p301 ($s='/') {header("Location: $s", true, 301); die();}
    public static function uri () {return array_shift(explode("?",$_SERVER['REQUEST_URI']));}
    public static function microtime ($start = 0) {
        $t = explode(' ', microtime());
        return number_format($t[0] + $t[1] - $start, 5, '.', '');
    }
    public static function encrypt ($s) {
        return md5(md5(_SALT).md5($s));
    }
    public static function tpl ($s="") {
        if ($s=='') return new template();
        $s = str_replace("::", "/", strtolower($s).".php");
        if (!file_exists(_TPL.$s)) {
            return self::p404("No this template. $s");
        }
        return new template(_TPL.$s);
    }
    public static function getDomain($url) {
        $url = strtolower(trim($url));
        if ($url=='') return "";
        if (substr($url,0,1)=='/') $url = substr($url,1);
        if (strpos($url,'http://')!==0 && strpos($url,'https://')!==0) $url = 'http://'.$url;
        $host = parse_url($url, PHP_URL_HOST);
        $ha = explode(".",$host);
        $c = count($ha);
        if ($c<=2) return $host;
        if ($ha[$c-2]=='co' || $ha[$c-2]=='com') return $ha[$c-3].'.'.$ha[$c-2].'.'.$ha[$c-1];//co.uk, co.ca, com.cn
        return $ha[$c-2].'.'.$ha[$c-1];
    }
	public static function parseIni($f)	{
		$ini =  parse_ini_file($f,true);
		$env = isset($ini['global']['env']) ? $ini['global']['env'] : 'dev';
		$combine = array_merge($ini['global'],$ini[$env]);
		$combine['channels'] = explode(',',$combine['channels']);
		return $combine;
	}
    private static function getCurlOpts($url, $dumpHeader=false, $redir=false)
    {
        $agents = array(
            "Baiduspider+(+http://www.baidu.com/search/spider.htm)",
        );
        $agents = array(
            "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.3 (KHTML, like Gecko) Chrome/4.0.223.11 Safari/532.3",
            "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.8 (KHTML, like Gecko) Chrome/4.0.302.2 Safari/532.8",
            "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)",
            "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1; .NET CLR 1.1.4322)",
            "Opera/9.20 (Windows NT 6.0; U; en)",
            "Opera/9.00 (Windows NT 5.1; U; en)",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.50",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.0",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1",
        );
        $cookie = "/tmp/curl_cookie_".self::getDomain($url);
        $options = array(   CURLOPT_URL             => $url,
                            CURLOPT_REFERER         => 'http://www.baidu.com/baidu?wd=sohu&tn=monline_dg',
                            CURLOPT_RETURNTRANSFER  => 1,
                            CURLOPT_AUTOREFERER     => 1,
                            CURLOPT_FOLLOWLOCATION  => 1,
                            CURLOPT_MAXREDIRS       => 2,//!!! just for fetch 1st jump coupon link
                            CURLOPT_TIMEOUT         => 600,//some pages has big content needed more transfer time
                            CURLOPT_CONNECTTIMEOUT  => 15,
                            CURLOPT_SSL_VERIFYHOST  => 0,
                            CURLOPT_SSL_VERIFYPEER  => 0,
                            CURLOPT_COOKIEJAR       => $cookie,
                            CURLOPT_COOKIEFILE      => $cookie,
                            CURLOPT_USERAGENT       => $agents[array_rand($agents)],
                        );  /*
        if ($dumpHeader) {
            $options[CURLOPT_HEADER] = 1;
            $options[CURLOPT_NOBODY] = 1;
            $options[CURLOPT_CUSTOMREQUEST] = 'HEAD';
        } else {
            $options[CURLOPT_HTTPGET] = 1;
        }
        if ($redir) {
            $options[CURLOPT_FOLLOWLOCATION] = 1;
            $options[CURLOPT_MAXREDIRS] = 20;
        }*/
        $ip = self::getRandomIp();
        if ($ip) $options[CURLOPT_INTERFACE] = $ip;
        return $options;
    }

    public static function readUrl($url, $dumpHeader=false, $redir=false) 
    {
        $ch = curl_init();
        $opts = self::getCurlOpts($url, $dumpHeader, $redir);
        curl_setopt_array($ch, $opts);
		$html = curl_exec($ch);
		$r = 0;
		$msg = curl_error($ch);
		while ($msg && $r<=1) {
			echo "[ " . date('Y-m-d H:i:s') . " ]" . "[ $msg ] on [ $url ]\n";
			echo "[ HTML size ".strlen($html)." ]\n";
			echo "[ Retry after 3s ]\n";
			sleep(1);
			$html = curl_exec($ch);
			$msg = curl_error($ch);
			$r++;
		}
        curl_close($ch);
        //@unlink($opts[CURLOPT_COOKIEFILE]);
        return $html;
    }

    public static function getRandomIp() 
    {
        $ip = false;
        if (file_exists(dirname(__FILE__).'/ips.txt')) {
            $x = file(dirname(__FILE__).'/ips.txt');
            $ip = trim($x[array_rand($x)]);
        }
        if (false && DIRECTORY_SEPARATOR=='/') { //is unix or linux
            if (!$x = @unserialize(file_get_contents('/tmp/xhosts'))) {
                exec('/sbin/ifconfig | grep "inet " | cut -d : -f 2 | cut -d " " -f 1', $x, $r); 
                foreach ($x as $k=>$v) {
                    if ($v=='127.0.0.1') unset($x[$k]);
                }
                file_put_contents('/tmp/xhosts', serialize($x));
            }   
            $ip = $x[array_rand($x)];
        }
        //trigger_error('USE IP: '.$ip, E_USER_NOTICE);
        return $ip;
    }

    public static function readUrls($urls, $dumpHeader=false) 
    {
        if (count($urls)==1) {
            return self::readUrl($urls[0]);
        }
        $mh = curl_multi_init();
        $cu = array();
        foreach ($urls as $i => $url) {
            $cu[$i] = curl_init();
            curl_setopt_array($cu[$i], self::getCurlOpts($url, $dumpHeader));
            curl_multi_add_handle($mh, $cu[$i]);
        }
        do {
            $n = curl_multi_exec($mh, $active);
        } while ($active);
        $res = array();
        foreach ($urls as $i => $url) {
            $res[$url] = curl_multi_getcontent($cu[$i]);
            curl_close($cu[$i]);
        }
        curl_multi_close($mh);
        return $res;        
    }

    public static function dumpJumpUrl ($url,$all=false)
    {
        //$cmd = "curl -isLI '$url' | grep '^Location' | awk '{print $2}'";
        $i = 0;
        $html = self::readUrl($url, true, $all);
        $m = array();
        while ($i<=3 && strpos($html, "503 Service Temporarily Unavailable")!==false) {
            $i++;
            echo "*";
            sleep($i*2);
            $html = self::readUrl($url, true, $all);
        }
        preg_match_all("%^Location: (.+?)\r$%mi", $html, $m);
        return $m[1];
    }

    public static function dumpJumpUrls ($urls)
    {
        $htmls = self::readUrls($urls, true);
        foreach ($urls as $url) {
            $m = array();
            preg_match_all("%^Location: (.+?)\r$%mi", $htmls[$url], $m);
            $htmls[$url] = $m[1];
        }
        return $htmls;
    }

	public static function gzdecode($data){
		if (function_exists('gzdecode')) return gzdecode($data);
		$g=tempnam(sys_get_temp_dir(),'ff');
		@file_put_contents($g,$data);
		ob_start();
		readgzfile($g);
		$d=ob_get_clean();
		unlink($g);
		return $d;
	}

}

/**
* template class
* support tags:
* {$var}, {$var['key']}
* {foreach $array as $k=>$v} ... {$v['key']} ... {/foreach}
*/
final class template
{
    private $tpl;
    private $data;

    public function __construct ($tpl="") {
        if ($tpl) $this->parse($tpl);
    }
    private function parse ($tpl) {
        if (!file_exists($tpl)) die("TPL $tpl not exists.");
        $s = php_strip_whitespace($tpl);//add cache later
        $s = $this->replace($s);
        //file_put_contents("php://memory", $s);
        $this->tpl = $s;
    }
    private function replace ($s) {
        $var = '\$([a-zA-Z][a-zA-Z0-9_]*?)';
        $arr = $var.'\[(\S+?)\]';
        $file = '([a-zA-Z][0-9a-zA-Z_]*?\.[a-z]{3,4})';
        $s = preg_replace("%\{$arr\}%",$this->phppack('echo isset($\\1[\\2]) ? $\\1[\\2] : $this->data["\\1"][\\2];'),$s);
        $s = preg_replace("%\{$var\|(.+?)\}%",$this->phppack('echo isset($\\1) ? $\\1 : (isset($this->data["\\1"]) ? $this->data["\\1"] : \\2);'),$s);//default
        $s = preg_replace("%\{$var\}%",$this->phppack('echo isset($\\1) ? $\\1 : $this->data["\\1"];'),$s);
        $s = preg_replace("%\{foreach\s+$var\s+as\s+(.+?)\}%",$this->phppack('foreach ($this->data["\\1"] as \\2):'),$s);
        $s = preg_replace("%\{/foreach\}%",$this->phppack('endforeach;'),$s);
        $s = preg_replace("%\{require\s+$file\}%e","\$this->replace(file_get_contents(_TPL.'\\1'))",$s);//include tpl
        $s = preg_replace("%\{if\s+$arr(\S*?)\}%",$this->phppack('if ($\\1[\\2]\\3) :'),$s);
        $s = preg_replace("%\{if\s+$var(\S*?)\}%",$this->phppack('if ($\\1\\2) :'),$s);
        $s = preg_replace("%\{/if\}%",$this->phppack('endif;'),$s);
        $s = preg_replace("%\{else\}%",$this->phppack('else:'),$s);
        //echo($s);
        return $s;
    }
    private function phppack ($s,$type='') {
        if ($type=='eval') return " ?".">".$s."<"."?php ";
        return "<"."?php ".$s." ?".">";
    }
    public function assign ($name, $value) {
        $this->data[$name] = $value;
    }
    public function display ($tpl="") {
        if ($tpl) $this->parse($tpl);
        foreach((array)$this->data as $k=>$v) eval('$'.$k."=".var_export($v,1).";");
        eval ($this->phppack($this->tpl,'eval'));
    }
}
